package com.robert.demo.common.aop;

import com.alibaba.fastjson.JSONObject;
import com.robert.common.commonutil.bean.vo.ResultData;
import com.robert.common.commonutil.exception.AppException;
import com.robert.demo.common.service.IResultValidator;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

/**
 * ValidationAspect:
 *
 * @author zhaoshengtao
 * @date 2024/03/20
 */
@Aspect
@Component
@Slf4j
public class ValidationAspect {
    /**
     * 用来根据beanName获取bean
     */
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 鉴权逻辑入库
     */
    @Around("@annotation(ValidateResult)")
    public Object validateResult(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法参数，基本上都是Request对象
        Object[] args = joinPoint.getArgs();
        // 执行原方法并获取结果
        Object result = joinPoint.proceed();
        Integer userId = null;
        try {
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取方法上的注解
            ValidateResult validateResult = signature.getMethod().getAnnotation(ValidateResult.class);
            // 获取鉴权逻辑对应的beanName
            String value = validateResult.value();
            // 获取入参的实体类型
            Class<?> paramType = validateResult.paramType();
            // 获取第一个方法参数，也就是请求VO
            Object arg = args[0];
            // 使用Class的newInstance()方法尝试实例化或者转换，前提是paramType所代表的类具有无参构造函数
            if (paramType.isInstance(arg)) { // 检查objectToConvert是否已经是paramType的实例或子类实例
                // 直接转换，无需重新实例化
                Object convertedObject = paramType.cast(arg);
                // 模拟获取当前登录用户的userId
                Field userIdField = convertedObject.getClass().getDeclaredField("userId");
                userIdField.setAccessible(true); // 如果该字段是私有的，需要设置为可访问
                userId = (Integer) userIdField.get(convertedObject);
            }
            // 从Spring容器中获取校验类的实例
            IResultValidator validator = (IResultValidator) applicationContext
                    .getBean(value);
            // 执行鉴权逻辑
            if (!validator.execute(result, userId)) {
                // 校验失败，抛出异常
                return ResultData.error("无访问权限");
            }
            log.info("校验通过， userId={}", userId);
        } catch (Exception e) {
            // 处理异常，例如找不到Bean或执行校验时发生的异常
            throw new RuntimeException("系统异常: " + e.getMessage(), e);
        }
        return result;
    }

}